home *** CD-ROM | disk | FTP | other *** search
/ MacHack 2000 / MacHack 2000.toast / pc / The Hacks / Easy as pi dcmd ƒ / pi.p < prev    next >
Encoding:
Text File  |  2000-06-23  |  9.1 KB  |  274 lines

  1. {    Easy as pi dcmd }
  2. {    Created at MacHack 2000 by Philippe Casgrain }
  3. {    philippe@casgrain.com }
  4.  
  5. {    This file is best viewed in a monospace font. }
  6.  
  7. {    This dcmd does the reverse of the 'pp' dcmd, that is given the proper  }
  8. {    MixedMode information it will return the hex value for the ProcInfoType. }
  9.  
  10. {    This hack is actually useful to non-C programmers since they don't have }
  11. {    access to the macros in MixedMode.h to build the ProcInfoType from  }
  12. {    scratch each time the source is compiled. }
  13.  
  14. {    The skeleton of this dcmd is based on the 'Blat' pascal dcmd, which was written }
  15. {    by Bo3b Johnson on 8/28/91. All of the code was written by PhC except for the }
  16. {    'LowerStr255' and 'NumberToHex' functions, which were taken from MacApp anyway. }
  17.  
  18. {    This dcmd compiles well under MPW 3.2 using the old style interfaces. I have not }
  19. {    attempted to make it compile under 3.3 and universal interfaces, mostly because }
  20. {    I use the Pascal compiler which is 68k only so the new routine names don't  }
  21. {    really matter. }
  22.  
  23. unit pi;
  24.  
  25. {$R-}
  26. { debug labels on. }
  27. {$D+}
  28.  
  29. interface
  30.  
  31.     uses
  32.         MemTypes, Packages, Scrap, {}
  33.         dcmd; { Macsbug interface routines. }
  34.  
  35.     { Public declaration for dcmdGlue. Must be in every dcmd. The name cannot be changed. }
  36.     procedure CommandEntry (paramPtr: dcmdBlockPtr);
  37.  
  38. implementation
  39.  
  40.     const
  41.         kHexDigits = '0123456789ABCDEF';    { Digits in base 16, for hex conversion. }
  42.     type
  43.         Str8 = string[8]; { When passing back hex numbers on the stack, best to use small ones. }
  44.  
  45.  
  46. {-------------------------------------------------------------------------------------------}
  47. { Comment by Bo3b Johnson }
  48. { Well, I stole this routine from MacApp utilities.  I want to lower case the strings so I }
  49. {    don't have case sensitivities.  This will do it, without using the toolbox. }
  50.     procedure LowerStr255 (var s: Str255);
  51.         var
  52.             i: Integer;
  53.     begin
  54.         for i := 1 to Length(s) do
  55.             if (s[i] in ['A'..'Z']) then
  56.                 s[i] := Chr(Ord(s[i]) + 32)
  57.     end; { LowerStr255 }
  58.  
  59.  
  60. {-------------------------------------------------------------------------------------------}
  61. { Comment by Bo3b Johnson }
  62. { Another handy routine stolen from MacApp to do the conversion on the dang strings.  I }
  63. {    only pass back Str8, since that is the maximum length, and stack space is limited in }
  64. {    Macsbug, and I don't want to waste it needlessly.  }
  65. {    Notably, this one handles negative LongInts properly, unlike the one distributed with }
  66. {    the dcmd samples. }
  67.     function NumberToHex (decNumber: univ LongInt): Str8;
  68.         var
  69.             i: Integer;
  70.             hexNumber: Str8;
  71.     begin
  72.         hexNumber[0] := Chr(8);
  73.         for i := 8 downto 1 do begin
  74.                 hexNumber[i] := kHexDigits[BAnd(decNumber, 15) + 1];
  75.                 decNumber := BSR(decNumber, 4);
  76.             end;
  77.         NumberToHex := hexNumber;
  78.     end; { NumberToHex }
  79.  
  80. { This function looks at the first parameter to pi, which should be the calling }
  81. { convention. If it is not understood, dump an error message. }
  82.     function ParseFirstParameter (var dumpString: Str255; var result: LongInt): boolean;
  83.         var
  84.             parseChar: Char;
  85.     begin
  86.         result := -1;
  87.         parseChar := dcmdGetNextParameter(dumpString);
  88.         LowerStr255(dumpString);
  89.         if dumpString = 'kpascalstackbased' then
  90.             result := 0;
  91.         if dumpString = 'kcstackbased' then
  92.             result := 1;
  93.         if dumpString = 'kregisterbased' then
  94.             result := 2;
  95.         if dumpstring = 'kthinkcstackbased' then
  96.             result := 5;
  97.         if dumpstring = 'kd0dispatchedpascalstackbased' then
  98.             result := 8;
  99.         if dumpstring = 'kd0dispatchedcstackbased' then
  100.             result := 9;
  101.         if dumpstring = 'kd1dispatchedpascalstackbased' then
  102.             result := 12;
  103.         if dumpstring = 'kstackdispatchedpascalstackbased' then
  104.             result := 14;
  105.         if dumpstring = 'kspecialcase' then
  106.             result := 15;
  107.  
  108.         ParseFirstParameter := (result >= 0);
  109.     end; { ParseFirstParameter }
  110.  
  111. { This shows the help message if the user simply typed 'pi' or 'help pi'. }
  112. { If there was an error parsing the dumpString in ParseFirstParameter above, }
  113. { explain that we could not figure out the calling convention (first parameter). }
  114.     procedure ShowHelpText (dumpString: Str255);
  115.  
  116.     begin
  117.         if (dumpString = '') then begin { there was no parameter or a help request, dump the help text }
  118.                 dcmdDrawLine('pi   kPascalStackBased | kCStackBased | kRegisterBased | kThinkCStackBased |');
  119.                 dcmdDrawLine('    kD0DispatchedPascalStackBased | kD0DispatchedCStackBased |');
  120.                 dcmdDrawLine('    kD1DispatchedPascalStackBased | kStackDispatchedPascalStackBased |');
  121.                 dcmdDrawLine('    kSpecialCase | result_size stack_parameter_1_size stack_parameter_2_size ...');
  122.                 dcmdDrawLine('');
  123.                 dcmdDrawLine('  Returns the ProcInfoType long word using the information provided');
  124.                 dcmdDrawLine('  (reverse of the pp dcmd). philippe@casgrain.com, MacHack 2000');
  125.             end
  126.         else begin { first parameter not understood }
  127.                 dumpString := Concat('  pi does not understand the "', dumpString, '" parameter.');
  128.                 dcmdDrawLine(dumpString);
  129.                 dcmdDrawLine('  Type "help pi" for more information.');
  130.             end;
  131.     end; { ShowHelpText }
  132.  
  133. { Writes the header of useful information if it was not written already. }
  134.     procedure WriteHeader (var headerWritten: Boolean; c: Integer; result, value: LongInt);
  135.         var
  136.             s: Str255;
  137.     begin
  138.         if not headerWritten then begin
  139.                 s := 'The ProcinfoType for a ';
  140.                 if (c = 0) or (value = 0) then { nothing to return on the stack so it must be a procedure }
  141.                     s := Concat(s, 'procedure')
  142.                 else
  143.                     s := Concat(s, 'function');
  144.  
  145.                 s := Concat(s, ' with the following parameters:');
  146.                 dcmdDrawLine(s);
  147.                 case result of
  148.                     0: 
  149.                         s := 'kPascalStackBased';
  150.                     1: 
  151.                         s := 'kCStackBased';
  152.                     2: 
  153.                         s := 'kRegisterBased';
  154.                     5: 
  155.                         s := 'kThinkCStackBased';
  156.                     8: 
  157.                         s := 'kD0DispatchedPascalStackBased';
  158.                     9: 
  159.                         s := 'kD0DispatchedCStackBased';
  160.                     12: 
  161.                         s := 'kD1DispatchedPascalStackBased';
  162.                     14: 
  163.                         s := 'kStackDispatchedPascalStackBased';
  164.                     15: 
  165.                         s := 'kSpecialCase';
  166.                     otherwise
  167.                         s := 'can''t happen!';
  168.                 end; { case }
  169.                 s := Concat('Calling convention   : ', s);
  170.                 dcmdDrawLine(s);
  171.  
  172.                 headerWritten := true;
  173.             end; { headerWritten }
  174.  
  175.     end; { WriteHeader }
  176.  
  177. { This just sets the right bits, starting at basebit, for the size of }
  178. { parameters to pass on the stack (including the return value). For more }
  179. { information, see IM:Mixed Mode Manager. }
  180.     procedure SetBits (var result: LongInt; baseBit: Integer; value: LongInt);
  181.     begin
  182.         case value of
  183.             1: 
  184.                 BSet(result, baseBit);
  185.             2: 
  186.                 BSet(result, baseBit + 1);
  187.             4:  begin
  188.                     BSet(result, baseBit);
  189.                     BSet(result, baseBit + 1);
  190.                 end;
  191.             otherwise { in this case, leave as-is (should be both clear }
  192.                 ;
  193.         end; { case }
  194.     end; { SetBits }
  195.  
  196. {-------------------------------------------------------------------------------------------}
  197.  
  198.  
  199. { This procedure is the main entry point for the dcmd.  It is the hook by which we get }
  200. {    called by MacsBug to do our thing. It is basically the chance to key off the command }
  201. {    line and do what it requests. }
  202.     procedure CommandEntry (paramPtr: DCmdBlockPtr);
  203.         var
  204.             parseChar: Char;
  205.             okParse, headerWritten: Boolean;
  206.             dumpString, s1, s2: Str255;
  207.             c, curBaseBit: Integer;
  208.             value, result: LongInt;
  209.             err: OSErr;
  210.  
  211.     begin
  212.         case paramPtr^.request of
  213.             dcmdInit: 
  214.                 ; { We have no initalizations to do in this very simple dcmd }
  215.  
  216.             dcmdDoIt:  begin { here the dcmd is being called with (hopefully) a command line of options }
  217.                     result := 0;
  218.                     if ParseFirstParameter(dumpString, result) then begin { We have the first parameter's string }
  219.                             c := 0; { count of extra parameters }
  220.                             curBaseBit := 2; { high-order bit to set }
  221.                             headerWritten := false;
  222.                             repeat
  223.                                 parseChar := dcmdGetNextExpression(value, okParse);
  224.                                 if okParse then begin
  225.                                         c := c + 1;
  226.                                         curBaseBit := curBaseBit + 2;
  227.  
  228.                                         WriteHeader(headerWritten, c, result, value);
  229.  
  230.                                         if c = 1 then begin { second parameter is size of result on the stack }
  231.                                                 NumToString(value, s1);
  232.                                                 s1 := Concat('Size of return value : ', s1);
  233.                                                 dcmdDrawLine(s1);
  234.                                             end
  235.                                         else begin { c > 1, we are looking at the size of parameters }
  236.                                                 NumToString(c - 1, s1);
  237.                                                 s2 := 'Size of parameter ';
  238.                                                 if c < 10 then
  239.                                                     s2 := Concat(s2, ' '); { add padding space! }
  240.                                                 s1 := Concat(s2, s1, ' : ');
  241.                                                 NumToString(value, s2);
  242.                                                 s1 := Concat(s1, s2, ' bytes');
  243.                                                 dcmdDrawLine(s1);
  244.                                             end; { c > 1 }
  245.  
  246.                                         SetBits(result, curBaseBit, value);
  247.  
  248.                                     end
  249.                                 else
  250.                                     WriteHeader(headerWritten, c, result, value);
  251.                             until parseChar = Chr(13); { end of parameter line }
  252.                             dcmdDrawLine('');
  253.                             s2 := NumberToHex(result);
  254.                             s1 := Concat('is: ', s2);
  255.                             dcmdDrawLine(s1);
  256.                             
  257. { An experiment in putting the result on the clipboard... }
  258. { You shouldn't be doing this since these calls may move memory and }
  259. { MacsBug can be called at interrupt time, when memory should *not* }
  260. { move. }
  261. {                            err := ZeroScrap;}
  262. {                            err := PutScrap(8, 'TEXT', @s2[1]);}
  263.                         end { if  }
  264.                     else
  265.                         ShowHelpText(dumpString);
  266.                 end; { dcmdDoIt }
  267.                 
  268.                 dcmdHelp:
  269.                     ShowHelpText(''  );
  270.         end; { case paramPtr^.request. }
  271.  
  272.     end; { CommandEntry }
  273.  
  274. end.